#include <iostream>
#include <armadillo>
#include "boost/date_time/posix_time/posix_time.hpp"
#include "boost/program_options.hpp"
#include <boost/mpi.hpp>

using namespace std;
using namespace arma;
namespace posix_time = boost::posix_time;
namespace mpi = boost::mpi;

#define M 1000
#define N 1000
#define TOTAL 3
#define SECONDS(d) ((double)d.total_milliseconds() / 1e3 )

#define MSGNE(s) { std::cerr << s; std::cerr.flush(); }
#define MSG(s) { std::cerr << s << std::endl; }

struct Clock
{
  posix_time::ptime start;
public:
  Clock() : start( posix_time::microsec_clock::local_time() ) {}
  posix_time::time_duration Duration() { return posix_time::microsec_clock::local_time()-start; }
  void Reset() { start = posix_time::microsec_clock::local_time(); }
};

void test_mul()
{
  MSGNE("MUL " << M << " x " << N << " " << TOTAL << " times ... ");
  Clock c;
  mat A = randu<mat>(M,N);
  for (int i = 0; i < TOTAL; i++) {
    MSGNE(" " << i);
    mat B = A*A;
  }
  MSG(SECONDS(c.Duration()) << " seconds.");
}

int main(int argc, char** argv)
{
  mpi::environment env(argc, argv);
  mpi::communicator world;
  //MSG("testlib " << world.rank());
  //test_mul();
  int a = world.rank();
  int s;
  mpi::reduce(world, a, s, std::plus<int>(), 0);
  if (world.rank() == 0) MSG("s=" << s);
  return 0;
}
